package com.xyq.friend.service.question.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.util.StringUtil;
import com.xyq.common.core.constants.CacheConstants;
import com.xyq.common.core.constants.Constants;
import com.xyq.common.core.domain.TableDataInfo;
import com.xyq.common.core.utils.ThreadLocalUtil;
import com.xyq.common.redis.service.RedisService;
import com.xyq.friend.domain.question.HotQuestion;
import com.xyq.friend.domain.question.Question;
import com.xyq.friend.domain.question.dto.QuestionSelectDTO;
import com.xyq.friend.domain.question.es.QuestionES;
import com.xyq.friend.domain.question.vo.QuestionDetailVO;
import com.xyq.friend.domain.question.vo.QuestionVO;
import com.xyq.friend.elasticsearch.QuestionRepository;
import com.xyq.friend.manager.QuestionCacheManager;
import com.xyq.friend.mapper.QuestionMapper;
import com.xyq.friend.service.question.QuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

@Service
public class QuestionServiceImpl implements QuestionService {

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private QuestionCacheManager questionCacheManager;

    @Autowired
    private RedisService redisService ;

    @Override
    public TableDataInfo list(QuestionSelectDTO questionSelectDTO) {
        // 1.先去 ES 里面查询 , 如果ES里面没有 ,就去数据库里查 ,
        long count = questionRepository.count();// 获取数量
        // 如果 ES里面没有数据 , 在数据库里找 , 同时刷新ES里的数据
        if (count <= 0) {
            refreshQuestion();
        }
        // 创建排序 , 按creteTime 排序
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        // 创建分页              es分页是从0开始 , 所以要-1 , 分页的同时按 createTime排序
        Pageable pageable = PageRequest.of(questionSelectDTO.getPageNum() - 1, questionSelectDTO.getPageSize(), sort);

        Integer difficulty = questionSelectDTO.getDifficulty();
        String keyword = questionSelectDTO.getKeyword();
        Page<QuestionES> questionESPageList;
        // 如果 没有难度和 题目内容搜索 全部内容 , 同时分页
        if (difficulty == null && StringUtil.isEmpty(keyword)) {
            questionESPageList = questionRepository.findAll(pageable);
        } else if (difficulty != null) {
            //按难度查询
            questionESPageList = questionRepository.findQuestionESByDifficulty(difficulty, pageable);
        } else if (StringUtil.isNotEmpty(keyword)) {
            // 按关键字查询
            questionESPageList = questionRepository.findByTitleOrContent(keyword, keyword, pageable);
        } else {
            // 有难度 , 有 关键字
            questionESPageList = questionRepository.findByTitleOrContentAAndDifficulty(keyword, keyword, difficulty, pageable);
        }
        //   获取 一共有多少条数据
        long total = questionESPageList.getTotalElements();
        //获取 查询出来的里面的数据
        List<QuestionES> questionESList = questionESPageList.getContent();

        // 列表只需要 id, 标题 ,难度 不需要那么多属性所以转成 QuestionVo
        List<QuestionVO> questionVOS = BeanUtil.copyToList(questionESList, QuestionVO.class);

        return TableDataInfo.success(questionVOS, total);
    }

    @Override
    public QuestionDetailVO detial(Long questionId , Long examId) {


        // 1.先去ES里查询
        QuestionES questionES = questionRepository.findById(questionId).orElse(null);
        QuestionDetailVO questionDetailVO = new QuestionDetailVO();
        if (questionES != null) {
            BeanUtil.copyProperties(questionES, questionDetailVO);
            // 如果竞赛id!=null
            if(examId != null){
                Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
                String submitCodeKey = getSubmitCodeKey(userId, questionId, examId);
                String userCode = redisService.getCacheObject(submitCodeKey, String.class);
                if(StringUtil.isNotEmpty(userCode)){
                    questionDetailVO.setDefaultCode(userCode);
                }
            }
            return questionDetailVO;
        }

        // 2. 查不到去数据库里查
        Question question = questionMapper.selectById(questionId);
        if (question == null) {
            return null;
        }
        // 3. 刷新ES
        refreshQuestion();
        BeanUtil.copyProperties(question, questionDetailVO);

        // 如果竞赛id!=null
        if(examId != null){
            Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
            String submitCodeKey = getSubmitCodeKey(userId, questionId, examId);
            String userCode = redisService.getCacheObject(submitCodeKey, String.class);
            if(StringUtil.isNotEmpty(userCode)){
                questionDetailVO.setDefaultCode(userCode);
            }
        }
        return questionDetailVO;
    }

    // 获取用户提交代码key
    private String getSubmitCodeKey(Long userId, Long questionId, Long examId) {
        return CacheConstants.SUBMIT_CODE + userId +":"+ examId+ ":" +questionId ;
    }

    // 上一题
    @Override
    public String preQuestion(Long questionId) {
        // 判断列表是否为空
        Long listSize = questionCacheManager.getListSize();
        if(listSize == null || listSize <= 0){
            // 为空 , 刷新缓存
            questionCacheManager.refresh() ;
        }
        // 获取当前 题目的上一题
       return questionCacheManager.preQuestion(questionId).toString();
    }

    @Override
    public String nextQuestion(Long questionId) {
        // 判断列表是否为空
        Long listSize = questionCacheManager.getListSize();
        if(listSize == null || listSize <= 0){
            // 为空 , 刷新缓存
            questionCacheManager.refresh() ;
        }
        // 获取当前 题目的下一题题
        return questionCacheManager.nextQuestion(questionId).toString();
    }


    @Override
    public List<HotQuestion> hotQuestion() {
        Long listSize = redisService.getListSize(getHotQuestionListKey());
       List<HotQuestion> hotQuestionList = null ;
        // 如果为空去数据库里查
        if(listSize == null || listSize<=0){
          hotQuestionList =   questionMapper.selectHotQuestionList();
          // 刷新缓存
            redisService.rightPushAll(getHotQuestionListKey() , hotQuestionList);
        }else{
            return redisService.getCacheListByRange(getHotQuestionListKey() , 0 , -1 , HotQuestion.class);
        }

        return hotQuestionList;
    }
    // 获取热门题目key
    private String getHotQuestionListKey(){
        return CacheConstants.HOT_QUESTION_LIST;
    }
    private void refreshQuestion() {
        // 从数据库获取数据 , 存储到ES里
        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>());
        if (CollectionUtils.isEmpty(questionList)) {
            return;
        }
        // 存储到ES里
        List<QuestionES> questionESList = BeanUtil.copyToList(questionList, QuestionES.class);
        questionRepository.saveAll(questionESList);
    }
}
